package com.atguigu.exam.service.impl;

import com.atguigu.exam.entity.AnswerRecord;
import com.atguigu.exam.entity.ExamRecord;
import com.atguigu.exam.entity.Paper;
import com.atguigu.exam.entity.Question;
import com.atguigu.exam.mapper.AnswerRecordMapper;
import com.atguigu.exam.mapper.ExamRecordMapper;
import com.atguigu.exam.service.AnswerRecordService;
import com.atguigu.exam.service.ExamService;
import com.atguigu.exam.service.KimiAiService;
import com.atguigu.exam.service.PaperService;
import com.atguigu.exam.vo.GradingResult;
import com.atguigu.exam.vo.StartExamVo;
import com.atguigu.exam.vo.SubmitAnswerVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 考试服务实现类
 */
@Service
@Slf4j
public class ExamServiceImpl extends ServiceImpl<ExamRecordMapper, ExamRecord> implements ExamService {

    @Autowired
    private ExamRecordMapper examRecordMapper;

    @Autowired
    private PaperService paperService;

    @Autowired
    private AnswerRecordMapper answerRecordMapper;

    @Autowired
    private AnswerRecordService answerRecordService;

    @Autowired
    private KimiAiService kimiAiService;
    /**
     * 开始考试 - 创建新的考试记录
     * @param startExamVo
     * @return
     */
    @Override
    public ExamRecord customCreateExam(StartExamVo startExamVo) {
        //1、校验是否已经存在对应名字的考试记录
        //名字相同，试卷ID相同，考试状态为进行中，不创建新的答题记录，返回旧的
        LambdaQueryWrapper<ExamRecord> examRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        examRecordLambdaQueryWrapper.eq(ExamRecord::getExamId, startExamVo.getPaperId());
        examRecordLambdaQueryWrapper.eq(ExamRecord::getStudentName, startExamVo.getStudentName());
        examRecordLambdaQueryWrapper.eq(ExamRecord::getStatus, "进行中");
        //直接返回旧的答题记录
        ExamRecord record = getOne(examRecordLambdaQueryWrapper);
        //对获取的答题记录进行校验，如果不为空，直接返回
        if (record != null) {
            return record;
        }

        //2、创建新的考试记录
        ExamRecord examRecord = new ExamRecord();
        //这里是对所有已知的数据进行赋值，方法一，直接copy，将属性名相同的直接进行赋值
        //BeanUtils.copyProperties(startExamVo, examRecord);
        // 方法二：分步设置，设置试卷ID
        examRecord.setExamId(startExamVo.getPaperId());
        // 设置考生姓名
        examRecord.setStudentName(startExamVo.getStudentName());
        //设置开启时间
        examRecord.setStartTime(LocalDateTime.now());
        //设置运行状态
        examRecord.setStatus("进行中");
        // 设置初始分数为0
        examRecord.setScore(0);
        // 设置初始窗口切换次数为0
        examRecord.setWindowSwitches(0);
        save(examRecord);
        return examRecord;
    }

    /**
     * 根据ID获取考试记录详情 - 查询具体考试结果
     * @param id 考试记录ID
     * @return
     */
    @Override
    public ExamRecord customGetExamRecordDetails(Integer id) {
        //先根据ID查询考试记录的信息
        ExamRecord examRecord = getById(id);
        //校验，如果为空，说明考试记录不存在，抛异常
        if (examRecord == null) {
            log.error("考试记录不存在！");
            throw new RuntimeException("考试记录不存在");
        }

        //根据考试记录的试卷ID，获取对应的试卷
        Paper paper = paperService.customPaperDetailById(Long.valueOf(examRecord.getExamId()));
        examRecord.setPaper(paper);

        //开始考试，加载答题记录列表，根据考试记录ID查询到的答题记录，后面需要按题目顺序重新排列
        List<AnswerRecord> answerRecords =
                answerRecordMapper.selectList(new QueryWrapper<AnswerRecord>().eq("exam_record_id", id));

        //按试卷题目顺序排序答题记录，要求前端展示顺序和考试时一致
        //先对试卷进行判断，符合条件再进行顺序修改
        //试卷不可为空，试卷题目不可为空，且答题记录列表不可为空
        if (paper != null && paper.getQuestions() != null && !answerRecords.isEmpty()) {
            //从试卷中提取的题目ID列表，保持了题目的原始顺序
            List<Long> question = paper.getQuestions().stream().map(Question::getId).collect(Collectors.toList());
            //对题目的答题记录根据题目的顺序进行排序
            answerRecords.sort((a, b) -> {
                //我们根据每个问题的下标来设置对应的答题记录的索引位置
                //获取第一个答题记录对应题目的索引位置
                int first = question.indexOf(a.getQuestionId().longValue());
                //获取第二个答题记录对应题目的索引位置
                int second = question.indexOf(b.getQuestionId().longValue());
                //比较两个索引位置，确定排序顺序
                return Integer.compare(first, second);
            });
        }
        //更新考试记录
        examRecord.setAnswerRecords(answerRecords);
        return examRecord;
    }

    /**
     * 提交答案 - 学生提交考试答案
     * @param examRecordId 考试记录ID
     * @param answers      答案列表
     */
    @Override
    public void customSubmitAnswers(Integer examRecordId, List<SubmitAnswerVo> answers) {
        //先根据考试记录ID获取考试记录
        ExamRecord examRecord = getById(examRecordId);
        //对考试记录进行校验，如果为空或者状态不是进行中状态，表示考试记录不存在或者已经完成对应考试
        if (examRecord == null || !"进行中".equals(examRecord.getStatus())) {
            throw new RuntimeException("考试记录不存在或已完成");
        }
        //保存答题记录
        //为了保存学生提交的答案，创建一个新的集合存放要存放的答题记录，大小和答案列表相同
        ArrayList<AnswerRecord> answerRecords = new ArrayList<>(answers.size());
        //保存每一条答案
        answers.forEach(answer -> {
            AnswerRecord answerRecord = new AnswerRecord(examRecordId, answer.getQuestionId(), answer.getUserAnswer());
            answerRecords.add(answerRecord);
            //批量优化，可以使用mybatis-plus service批量方法进行批量
            //answerRecordMapper.insert(answerRecord);
        });
        //批量插入数据
        answerRecordService.saveBatch(answerRecords);

        //修改考试记录对应的状态，进行中到已完成，结束时间为当前时间
        examRecord.setStatus("已完成");
        examRecord.setEndTime(LocalDateTime.now());
        //更新考试记录
        updateById(examRecord);

        // 4. 自动调用AI判卷
        log.info("试卷提交完成，开始自动AI智能判卷，考试记录ID: {}", examRecordId);
        try {
            //进行判卷
            customAiGrageExam(examRecordId);
            log.info("自动AI判卷完成，考试记录ID: {}", examRecordId);
        } catch (Exception e) {
            // 判卷失败不影响提交，但记录错误
            log.error("自动AI判卷失败，考试记录ID: {}, 错误: {}", examRecordId, e.getMessage());

        }
    }

    /**
     * AI自动批阅 - 触发试卷智能批阅
     * @param examRecordId
     * @return
     */
    @Override
    public ExamRecord customAiGrageExam(Integer examRecordId) {
        /*
        整体思路：
            宏观:获取考试记录相关的信息（考试记录对象 考试记录答题记录 考试对应试卷）
            进行循环判断（1.答题记录进行修改 2.总体提到总分数 总正确数量）  修改考试记录（状态 -》 已批阅  修改 -》 总分数）   进行ai评语生成（总正确的题目数量）
            修改考试记录表  返回考试记录对象
         */

        //1.根据考试记录ID获取考试记录和相关的信息（试卷和答题记录）
        ExamRecord examRecord = customGetExamRecordDetails(examRecordId);
        //获取考试记录的试卷信息
        Paper paper = examRecord.getPaper();
        //如果试卷信息为空，说明试卷被删除，抛异常
        if (paper == null) {
            examRecord.setStatus("已批阅");
            examRecord.setAnswers("考试对应的试卷被删除！无法进行成绩判定！");
            updateById(examRecord);
            throw new RuntimeException("考试对应的试卷被删除！无法进行成绩判定！");
        }
        //获取答题记录
        List<AnswerRecord> answerRecords = examRecord.getAnswerRecords();
        //进行校验，答题记录为空，表示没有做卷子，直接修改，不需要进入后面的循环，提高性能
        if (ObjectUtils.isEmpty(answerRecords)) {
            //没有提交，也是已批阅，赋值为
            examRecord.setStatus("已批阅");
            examRecord.setScore(0);
            //设置评语，
            examRecord.setAnswers("你没有做题，请反思自己，联系老师重新考试！");
            //更新
            updateById(examRecord);
            //返回结果
            return examRecord;
        }

        //2.进行循环的判卷 1.记录总分数 2.记录正确题目数量 3. 修改每个答题记录的状态
        //得分，是否正确有三种状态： 0 1 2,这里的2只适用于简答题，当简答题的分数介于0到满分之间的时候，赋值为2
        //通过调用AI获取试卷的评语
        //正确题目的数量
        int totaltrue = 0;
        //总得分
        int totalScore = 0;

        //在判卷过程中报错，继续判卷！ 某个记录错了，后续还需要继续判卷，需要使用for + try +catch的结合模板
        //将正确题目转成map,方便每次判断获取正确答案
        Map<Long, Question> questionMap = paper.getQuestions().stream().collect(Collectors.toMap(Question::getId, q -> q));
        //循环整个答题记录集合
        for (AnswerRecord answerRecord : answerRecords) {
            try {
                //1.先获取 答题记录对应的题目对象
                Question question = questionMap.get(answerRecord.getQuestionId().longValue());
                //获取正确答案
                String systemAnswer = question.getAnswer().getAnswer();
                //获取答题记录对应的答案
                String userAnswer = answerRecord.getUserAnswer();

                //这里因为前端传递记录正确和错误的格式是T和F，数据库中判断题正确与否的存储格式为
                // 那么需要转换成true false
                if ("JUDGE".equalsIgnoreCase(question.getType())) {
                    userAnswer = normalizeJudgeAnswer(userAnswer);
                }
                if (!"TEXT".equals(question.getType())) {
                    //2.判断题目类型(选择和判断直接判卷)
                    if (systemAnswer.equalsIgnoreCase(userAnswer)) {
                        answerRecord.setIsCorrect(1); //正确
                        answerRecord.setScore(question.getPaperScore().intValue());
                    } else {
                        answerRecord.setIsCorrect(0); //正确
                        answerRecord.setScore(0);
                    }
                } else {
                    //3.简答题进行ai判断
                    //简答题实现逻辑在KimiAiServiceImpl中实现了，直接调用即可
                    //参数为答题记录对应的题目对象，用户的答案，这个简答题的满分
                    GradingResult result =
                            kimiAiService.gradingTextQuestion(question,userAnswer,question.getPaperScore().intValue());
                    //这个结果是自定义的VO类型，下面需要对这个result结果进行处理
                    /*
                        private Integer score;
                        private String feedback;
                        private String reason;
                     */
                    //直接设置分数即可，这个为简答题的判分
                    answerRecord.setScore(result.getScore());
                    //ai评价为正确就将feedback的结果赋值
                    //ai评价非正确就将reason的结构赋值
                    //是否正确 （满分为1 0分为0 半正确半错误为2）
                    //错误，赋值0，评价写错误原因reason
                    if (result.getScore() == 0){
                        answerRecord.setIsCorrect(0);
                        answerRecord.setAiCorrection(result.getReason());

                    }else if (result.getScore() == question.getPaperScore().intValue()){//正确，赋值1，评价写Feedback
                        answerRecord.setIsCorrect(1);
                        answerRecord.setAiCorrection(result.getFeedback());
                    }else{//半对半错，赋值2，评价也写reason
                        answerRecord.setIsCorrect(2);
                        answerRecord.setAiCorrection(result.getReason());
                    }
                }
            } catch (Exception e) {
                //这里是判断失败的操作
                answerRecord.setScore(0);
                answerRecord.setIsCorrect(0);
                answerRecord.setAiCorrection("判题过程出错！");
            }
            //进行记录修改
            //进行实际分数赋值，走到这里的，一定都是批阅成功的试题，对他们的分数相加，无论多少分，直接相加即可
            totalScore += answerRecord.getScore();
            //正确题目数量累加，只有当Is_Correct的值为1，表示正确时，正确题目数量才可以+1
            if (answerRecord.getIsCorrect() == 1) {
                totaltrue++;
            }
        }
        //批量更新答题记录
        answerRecordService.updateBatchById(answerRecords);

        //进行ai生成评价，进行考试记录修改和完善
        //传入的参数为，实际分数，满分分数，总题目数，正确题目数
        String summary = kimiAiService.
                buildSummary(totalScore, paper.getTotalScore().intValue(), paper.getQuestionCount(), totaltrue);
        //设置考试记录的实际分数
        examRecord.setScore(totalScore);
        //设置考试记录的生成的Ai评价
        examRecord.setAnswers(summary);
        //修改考试记录的状态为已批阅
        examRecord.setStatus("已批阅");
        //对考试记录进行更新
        updateById(examRecord);

        return examRecord;
    }

    /**
     * 标准化判断题答案，将T/F转换为TRUE/FALSE
     * @param answer 原始答案
     * @return 标准化后的答案
     */
    private String normalizeJudgeAnswer(String answer) {
        if (answer == null || answer.trim().isEmpty()) {
            return "";
        }

        String normalized = answer.trim().toUpperCase();
        switch (normalized) {
            case "T":
            case "TRUE":
            case "正确":
                return "TRUE";
            case "F":
            case "FALSE":
            case "错":
                return "FALSE";
            default:
                return normalized;
        }
    }
}
